;physical memory manager in real mode 
;get memory BIOS interrupt routines only 
;work in real mode 

%define _PMM_REAL_MAC_EXTERN_OR_GLOBAL_ 1 
%define _PMM_REAL_ASM_ 1 

%include"../include/pmm_real.mac" 
%include"../include/utils.mac" 

[section .text] 
;int 0x15,AX=0xe801,get memory size > 16MB 
;Typical Output: 
;AX = CX = extended memory between 1M and 16M, in K (max 3C00h = 15MB)
;BX = DX = extended memory above 16M, in 64K blocks 

;input:none 
;output:[memory_size_kb],in kb 

get_memory_size: 
	push eax 
	push ebx 
	push ecx 
	push edx 
	pushfd  

	;clear eax,ebx,edx
	CLEAR_REGS_MULTI_XOR eax,ebx,edx

	;int call 
	mov ax,0xe801 
	int 0x15 
	jc .error   
	cmp ah,0x86 ;unsupported function  
	jz .error   
	cmp ah,0x80 ;invalid command  
	jz .error
	cmp cx,0 
	jz .use_ax ;cx=0  
	mov word[memory_size_kb],ax  
	;dx*64KB 
	shl edx,16 
	add dword[memory_size_kb],edx 
	jmp .exit  

.use_ax: ;ax and bx 
	add word[memory_size_kb],ax 
	;bx*64kb 
	shl ebx,16 
	add dword[memory_size_kb],ebx 
	jmp .exit 

.error: 
	mov dword[memory_size_kb],0 
.exit: 
	popfd  
	pop edx 
	pop ecx 
	pop ebx  
	pop eax 
	ret  


;routines to get memory entries  
;input:none 
;output:memory entries  
get_memory_entries:	 
	push eax 
	push ebx 
	push ecx 
	push edx 
	push edi 
	pushf    

	;xor edx;edi
	CLEAR_REGS_MULTI_XOR edx,edi

	mov edx,E820_MAGIC_NUM ;magic number:SMAP  
	mov edi,memory_map_entries  
.next_entry: 
	mov eax,INT15_E820  
	mov ecx,ENTRY_SIZE 
	int 0x15 
	jc .error 
	cmp eax,E820_MAGIC_NUM 
	jnz .error 
	cmp ebx,0 ;only one entry  
	jz .error 
	cmp cl,0 
	jz .bad_entry ;bad entry,skip  
	cmp cl,20 
	jbe .no_text 
	test byte[ENTRY_ACPI_OFFSET],0 ;ignore this entr? 
	je .bad_entry  

.no_text: 
	mov eax,dword[ENTRY_LEN_LOW_OFFSET] 
	xor eax,dword[ENTRY_LEN_HIGH_OFFSET] 
	jz .bad_entry 
	jmp .good_entry ;good entry 
	
.bad_entry: ;bad entry,skip  
	add edi,ENTRY_SIZE 
	jmp .next_entry 

.good_entry:  
	inc word[memory_entry_count] 
	add edi,ENTRY_SIZE 
	jmp .next_entry 

.error: ;read error  
	popf   
	pop edi 
	pop edx 
	pop ecx  
	pop ebx 
	pop eax 
	ret 

;phisical memory manager get memory information(size,map,etc) `
;input:none
;output:none 
pmm_get_memory_info: 
	call get_memory_size ;get memory size  
	call get_memory_entries ;get memory entries  
	ret 

[section .data] 
	;memory map entries 
	memory_map_entries: 
		%rep MEM_ENTRY_MAX 
			istruc memory_map_entry 
				at memory_map_entry.base,dq 0 
				at memory_map_entry.length,dq 0 
				at memory_map_entry.type,dd 0 
				at memory_map_entry.acpi_attr,dd 1 
			iend 
		%endrep  

	memory_entry_count dw 00 ;store entry count  
	memory_size_kb  dd 00 ;bios detected memory size in kb  
